use std::{collections::HashMap, sync::Arc};

use boardinfo::boardinfo_for_each;
use monitor::{Monitor, MonitorCommand};
use virt::boardinfo_aarch64_virt;

struct AvailableBoards;

pub(crate) fn monitor_command_boardinfo_register(mon: &Monitor) {
    boardinfo_aarch64_virt();

    mon.register_command("boardinfo", Arc::new(AvailableBoards)).unwrap();
}

impl MonitorCommand for AvailableBoards {
    fn mon_protocol_exec(&self, args: &monitor::Protocol) -> monitor::MonResult<monitor::Protocol> {
        let board = args.get("board");
        let mut hash = HashMap::new();
        if let Some(b) = board {
            boardinfo_for_each(|key, info| {
                if b == key {
                    hash.insert("info_long".to_string(), info.info_long().to_string());
                }
            });
        } else {
            boardinfo_for_each(|key, info| {
                hash.insert(key.to_string(), info.info().to_string());
            });
        }
        Ok(hash)
    }

    fn mon_readline_arg_type(&self) -> Option<&'static str> {
        Some("board:*?")
    }

    fn mon_readline_completer(
        &self,
        args: &[&str],
        is_space: bool,
    ) -> Option<monitor::CompleterSuggestion> {
        let mut v = vec![];
        boardinfo_for_each(|key, _| {
            if args.is_empty() || args.len() == 1 && !is_space && key.starts_with(args[0]) {
                v.push(key.to_string());
            }
        });

        Some(monitor::CompleterSuggestion::create(monitor::CompleterPosFrom::Deafult, v, is_space))
    }

    fn mon_readline_exec(
        &self,
        args: &HashMap<String, String>,
        printer: &monitor::MonitorPrinter,
    ) -> monitor::MonResult<()> {
        let board = args.get("board");
        if let Some(b) = board {
            boardinfo_for_each(|key, info| {
                if b == key {
                    printer.print(info.info_long().to_string());
                }
            });
        } else {
            boardinfo_for_each(|key, info| printer.print(format!("{:<13} - {}", key, info.info())));
        }
        Ok(())
    }

    fn mon_readline_help(&self) -> String {
        String::from("可用 board 信息")
    }

    fn mon_readline_long_help(&self) -> Option<String> {
        Some(String::from("boardinfo [board] - 获取 board 详细信息"))
    }
}
